package com.wande.dataplatform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wande.common.core.exception.ServiceException;
import com.wande.common.core.utils.MapstructUtils;
import com.wande.common.encrypt.utils.EncryptUtils;
import com.wande.common.mybatis.core.page.PageQuery;
import com.wande.common.mybatis.core.page.TableDataInfo;
import com.wande.common.redis.utils.RedisUtils;
import com.wande.dataplatform.domain.SystemConfig;
import com.wande.dataplatform.domain.bo.SystemConfigBo;
import com.wande.dataplatform.domain.vo.SystemConfigVO;
import com.wande.dataplatform.mapper.SystemConfigMapper;
import com.wande.dataplatform.service.ISystemConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Connection;
import java.sql.DriverManager;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 系统配置服务实现
 *
 * @author wande
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SystemConfigServiceImpl implements ISystemConfigService {

    private final SystemConfigMapper baseMapper;
    
    private static final String CONFIG_CACHE_KEY = "dataplatform:config:";
    private static final Duration CACHE_DURATION = Duration.ofHours(1);

    @Override
    public TableDataInfo<SystemConfigVO> queryPageList(SystemConfigBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SystemConfig> wrapper = buildQueryWrapper(bo);
        Page<SystemConfigVO> page = baseMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    @Override
    public List<SystemConfigVO> queryList(SystemConfigBo bo) {
        LambdaQueryWrapper<SystemConfig> wrapper = buildQueryWrapper(bo);
        return baseMapper.selectVoList(wrapper);
    }

    @Override
    public SystemConfigVO queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    @Override
    public String getConfigValue(String configKey) {
        // 先从缓存获取
        String cacheKey = CONFIG_CACHE_KEY + configKey;
        String cachedValue = RedisUtils.getCacheObject(cacheKey);
        if (StrUtil.isNotBlank(cachedValue)) {
            return cachedValue;
        }

        // 从数据库查询
        LambdaQueryWrapper<SystemConfig> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SystemConfig::getConfigKey, configKey);
        wrapper.eq(SystemConfig::getStatus, 1);
        SystemConfig config = baseMapper.selectOne(wrapper);
        
        if (config == null) {
            return null;
        }

        String value = config.getConfigValue();
        
        // 解密加密的配置
        if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1 && StrUtil.isNotBlank(value)) {
            try {
                value = EncryptUtils.decryptByAes(value, "dataplatform1234");
            } catch (Exception e) {
                log.error("解密配置失败: {}", configKey, e);
            }
        }

        // 缓存配置值
        RedisUtils.setCacheObject(cacheKey, value, CACHE_DURATION);
        
        return value;
    }

    @Override
    public List<SystemConfigVO> queryByType(String configType) {
        LambdaQueryWrapper<SystemConfig> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SystemConfig::getConfigType, configType);
        wrapper.eq(SystemConfig::getStatus, 1);
        wrapper.orderByAsc(SystemConfig::getDisplayOrder);
        return baseMapper.selectVoList(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(SystemConfigBo bo) {
        SystemConfig config = MapstructUtils.convert(bo, SystemConfig.class);
        
        // 加密敏感配置
        if (bo.getIsEncrypted() != null && bo.getIsEncrypted() == 1 && StrUtil.isNotBlank(bo.getConfigValue())) {
            try {
                config.setConfigValue(EncryptUtils.encryptByAes(bo.getConfigValue(), "dataplatform1234"));
            } catch (Exception e) {
                log.error("加密配置失败", e);
                throw new ServiceException("加密配置失败");
            }
        }
        
        boolean result = baseMapper.insert(config) > 0;
        if (result) {
            refreshCache();
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(SystemConfigBo bo) {
        SystemConfig config = MapstructUtils.convert(bo, SystemConfig.class);
        
        // 加密敏感配置
        if (bo.getIsEncrypted() != null && bo.getIsEncrypted() == 1 && StrUtil.isNotBlank(bo.getConfigValue())) {
            try {
                config.setConfigValue(EncryptUtils.encryptByAes(bo.getConfigValue(), "dataplatform1234"));
            } catch (Exception e) {
                log.error("加密配置失败", e);
                throw new ServiceException("加密配置失败");
            }
        }
        
        boolean result = baseMapper.updateById(config) > 0;
        if (result) {
            refreshCache();
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchUpdate(List<SystemConfigBo> configs) {
        for (SystemConfigBo bo : configs) {
            updateByBo(bo);
        }
        refreshCache();
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteByIds(List<Long> ids) {
        boolean result = baseMapper.deleteBatchIds(ids) > 0;
        if (result) {
            refreshCache();
        }
        return result;
    }

    @Override
    public Map<String, Object> validateConfig(String configType) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            switch (configType) {
                case "DORIS":
                    return testDorisConnection();
                case "DOLPHINSCHEDULER":
                    return testDolphinSchedulerConnection();
                default:
                    result.put("success", true);
                    result.put("message", "配置验证通过");
            }
        } catch (Exception e) {
            log.error("配置验证失败", e);
            result.put("success", false);
            result.put("message", "配置验证失败: " + e.getMessage());
        }
        
        return result;
    }

    @Override
    public Map<String, Object> testDorisConnection() {
        Map<String, Object> result = new HashMap<>();
        
        try {
            String jdbcUrl = getConfigValue("doris.jdbc.url");
            String username = getConfigValue("doris.username");
            String password = getConfigValue("doris.password");
            
            if (StrUtil.isBlank(jdbcUrl) || StrUtil.isBlank(username)) {
                result.put("success", false);
                result.put("message", "Doris连接配置不完整");
                return result;
            }
            
            // 测试连接
            try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
                result.put("success", true);
                result.put("message", "Doris连接测试成功");
                result.put("version", conn.getMetaData().getDatabaseProductVersion());
            }
        } catch (Exception e) {
            log.error("Doris连接测试失败", e);
            result.put("success", false);
            result.put("message", "Doris连接测试失败: " + e.getMessage());
        }
        
        return result;
    }

    @Override
    public Map<String, Object> testDolphinSchedulerConnection() {
        Map<String, Object> result = new HashMap<>();
        
        try {
            String apiUrl = getConfigValue("dolphinscheduler.api.url");
            String token = getConfigValue("dolphinscheduler.token");
            
            if (StrUtil.isBlank(apiUrl) || StrUtil.isBlank(token)) {
                result.put("success", false);
                result.put("message", "DolphinScheduler连接配置不完整");
                return result;
            }
            
            // TODO: 实际调用DolphinScheduler API测试连接
            result.put("success", true);
            result.put("message", "DolphinScheduler连接测试成功");
        } catch (Exception e) {
            log.error("DolphinScheduler连接测试失败", e);
            result.put("success", false);
            result.put("message", "DolphinScheduler连接测试失败: " + e.getMessage());
        }
        
        return result;
    }

    @Override
    public String exportConfig(String configType) {
        List<SystemConfigVO> configs = queryByType(configType);
        return JSONUtil.toJsonStr(configs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean importConfig(String configJson) {
        try {
            List<SystemConfigBo> configs = JSONUtil.toList(configJson, SystemConfigBo.class);
            for (SystemConfigBo bo : configs) {
                // 检查配置是否存在
                LambdaQueryWrapper<SystemConfig> wrapper = Wrappers.lambdaQuery();
                wrapper.eq(SystemConfig::getConfigKey, bo.getConfigKey());
                SystemConfig existing = baseMapper.selectOne(wrapper);
                
                if (existing != null) {
                    bo.setId(existing.getId());
                    updateByBo(bo);
                } else {
                    insertByBo(bo);
                }
            }
            refreshCache();
            return true;
        } catch (Exception e) {
            log.error("导入配置失败", e);
            throw new ServiceException("导入配置失败: " + e.getMessage());
        }
    }

    @Override
    public void refreshCache() {
        // 清除所有配置缓存
        RedisUtils.deleteKeys(CONFIG_CACHE_KEY + "*");
        log.info("配置缓存已刷新");
    }

    /**
     * 构建查询条件
     */
    private LambdaQueryWrapper<SystemConfig> buildQueryWrapper(SystemConfigBo bo) {
        LambdaQueryWrapper<SystemConfig> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StrUtil.isNotBlank(bo.getConfigKey()), SystemConfig::getConfigKey, bo.getConfigKey());
        wrapper.eq(StrUtil.isNotBlank(bo.getConfigType()), SystemConfig::getConfigType, bo.getConfigType());
        wrapper.eq(bo.getStatus() != null, SystemConfig::getStatus, bo.getStatus());
        wrapper.orderByAsc(SystemConfig::getConfigType);
        wrapper.orderByAsc(SystemConfig::getDisplayOrder);
        return wrapper;
    }
}
